/*
   Copyright 2011 Brook Smith

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
package org.xempot.xform;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

public class TemplateLoader {

	private static final QName Q_NAME = new QName("id");
	private static final String UTF_8 = "utf-8";
	private static final String TEMPLATE = "template";
	private static final String NS = "http://code.google.com/p/xempot";

	/**
	 * Convienience method to return an XMLEventReader
	 * 
	 * @param in
	 * @return
	 * @throws XMLStreamException
	 */
	private static XMLEventReader getXmlEventReader(InputStream in) throws XMLStreamException {
		javax.xml.stream.XMLInputFactory factory = javax.xml.stream.XMLInputFactory.newFactory();
		return factory.createXMLEventReader(in, UTF_8);
	}

	/**
	 * 
	 * @param file
	 * @return map of the snippits contained in the template
	 * @throws IOException
	 * @throws XMLStreamException
	 */
	public static Map<String, String> loadTemplate(File file) throws IOException, XMLStreamException {
		return loadTemplate(new FileInputStream(file));
	}

	/**
	 * 
	 * @param InputStream
	 * @return map of the snippits contained in the template
	 * @throws IOException
	 * @throws XMLStreamException
	 */

	public static Map<String, String> loadTemplate(InputStream inputStream) throws IOException, XMLStreamException {
		Map<String, String> res = new HashMap<String, String>();

		if (inputStream ==  null) {
			throw new NullPointerException("The template InputStream is null");
		}
		
		try {
			XMLEventReader eventReader = getXmlEventReader(inputStream);

			while (eventReader.hasNext()) {
				XMLEvent event = eventReader.nextEvent();

				if (event.isStartElement()) {
					StartElement startElement = event.asStartElement();
					
					if (startElement.getName().getLocalPart().equals(TEMPLATE) && startElement.getName().getNamespaceURI().equals(NS)) {
						// read the snippit into the map
						String content = readSnippit(eventReader);
						Attribute attribute = startElement.getAttributeByName(Q_NAME);
						res.put(attribute.getValue(), content);

						// System.out.println("Offset:"+startElement.getLocation().getCharacterOffset());
					}
				}
			}

		} finally {
			inputStream.close();
		}
		return res;
	}

	public static Map<String, String> loadTemplate(String file) throws IOException, XMLStreamException {
		return loadTemplate(new File(file));
	}

	public static void main(String[] args) {
		try {
			System.out.println(loadTemplate("src/resource/template.xml"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (XMLStreamException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private static String readSnippit(XMLEventReader eventReader) throws IOException, XMLStreamException {
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		XMLEventWriter eventWriter = XMLOutputFactory.newInstance().createXMLEventWriter(outputStream, UTF_8);

		// read every thing up to the snippit end tag
		while (eventReader.hasNext()) {
			XMLEvent event = eventReader.nextEvent();

			if (event.isEndElement()) {
				EndElement endElement = event.asEndElement();
				if (endElement.getName().getLocalPart().equals(TEMPLATE)) {
					eventWriter.flush();
					eventWriter.close();
					outputStream.flush();
					outputStream.close();
					return outputStream.toString(UTF_8);
				}
			}
			eventWriter.add(event);
		}

		return null;
	}

}
